/*
 * queuebuf.hpp
 *
 *  Created on: 2015��10��9��
 *      Author: dylan
 */

#ifndef _DM_QUEUEBUF_HPP_
#define _DM_QUEUEBUF_HPP_

namespace NDm{

template<typename TValue,typename TSize=unsigned int,typename TPos=TSize >
class TQueueBuf{
public:
	TQueueBuf( TValue* buf=0,const TSize& size=0 ):m_buf(buf),m_size(size),m_pos(0){
	}

	inline void init( TValue* buf,const TSize& size ){
		m_buf = buf;
		m_size = size;
		m_pos = 0;
	}

	inline const TValue* data()const{
		return m_buf;
	}

	inline TValue* data(){
		return m_buf;
	}

	inline void movePos( const TSize& n ){
		m_pos += n;
	}

	inline const TValue& data( const TSize& p )const{
		return m_buf[p%m_size];
	}

	inline bool isEmpty()const{
		return m_pos==0;
	}

	inline bool isFull()const{
		return m_pos>=m_size;
	}

	inline const TSize& size()const{
		return m_size;
	}

	inline const TPos& length()const{
		return m_pos;
	}

	inline TSize avaliable()const{
		return m_size - m_pos;
	}

	inline void clear(){
		m_pos = 0;
	}

	void push( const TValue& v ){
		if( m_pos<m_size ){
			m_buf[m_pos] = v;
			++m_pos;
		}else{
			for( TSize i=1;i<m_pos;++i )
				m_buf[i-1] = m_buf[i];
			m_buf[m_pos-1] = v;
		}
	}

	void push( const TValue* v,TSize n ){
		if( n>=m_size ){
			v += n-m_size;
			for( TSize i=0;i<m_size;++i )
				m_buf[i] = v[i];
		}else{
			if( n>avaliable() )
				pop( n-avaliable() );
			for( TSize i=0;i<n;++i,++m_pos )
				m_buf[m_pos] = v[i];
		}
	}

	void pop( const TSize& n=1 ){
		if( n>=m_pos ){
			clear();
		}else{
			for( TSize i=n;i<m_pos;++i )
				m_buf[i-n] = m_buf[i];
			m_pos -= n;
		}
	}

	TSize pop( TValue* buf,const TSize& size ){
		TSize rt = size;
		if( rt>m_pos )
			rt = m_pos;

		for( TSize i=0;i<rt;++i )
			buf[i] = m_buf[i];
		pop(rt);
		return rt;
	}
private:
	TValue* m_buf;
	TPos m_pos;
	TSize m_size;
};

}

#endif /* QUEUEBUF_HPP_ */
